import File from './File'
import {procedureShadow} from '../designer/procedure'
let jsPlumb = window.jsPlumb
export  default  class Procedure extends File{
    constructor(name, type, parent) {
        super()
        this.content = "(){}"
        this.originContent = '{"nodes":[]}'
    }
    write(content) {
        this.originContent = content
        let obj = JSON.parse(this.originContent)
        //寻找start,从start开始
        //解析start内容，如果是“开始”，则无参数，如果是变量以逗号隔开，则为参数列表
        //解析assign内容，为赋值，//格式单独赋值：a = b 批量赋值:[a,b,c] = [d,f,g]，数组赋值a := b
        //解析data内容，变量声明，//格式a,b,c
        //解析judge内容，
        //解析end内容，如果是"结束"，无返回，如果是变量，则返回
        //解析request内容，网络请求
        //解析subprocess，
        let start = this.getStart(obj)
        if(!start) {
            throw "没有开始节点"
            return
        }
        this.content = this.parse(obj, start)
        console.log(this.content)
    }
    getID(obj, id) {
        let nodes = obj.nodes
        for(let node of nodes) {
            if(node.id === id) {
                return node
            }
        }
        return false
    }
    getStart(obj) {
        let nodes = obj.nodes
        for(let node of nodes) {
            if(node.type === "start") {
                return node
            }
        }
        return false
    }
    mkView(el, fn,drag) {
        let obj = JSON.parse(this.originContent)
        let start = this.getStart(obj)
        if(!start) {
            throw "没有开始节点"
            return
        }
        this.mkNode(el, start, fn, obj,drag)
    }
    mkNode(el,node,fn,obj,drag){
        let shadow =  el.children("#" + node.id)
        if(shadow.length == 0) {
            shadow = procedureShadow[node.type].clone()
            shadow.attr('id', node.id)
            shadow.css("left", node.left + 'px')
            shadow.css("top", node.top + 'px')
            shadow.css("position","absolute")
            for (let attr in node.attributes) {
                shadow.attr(attr, node.attributes[attr])
            }
            shadow.html(node.content + '<i class = "fa fa-arrows-alt alt" contenteditable="false"></i>')
            el.append(shadow)
            drag(shadow)
        }
        let spans = node.spans
        let endPoints = fn(node.id, node.type)
        switch(node.type) {
            case 'start':
            case 'assign':
            case 'data':
            case 'subprocess':
                if(spans.length == 1) {
                    let target = node.spans[0].target
                    let targetNode = this.getID(obj, target)
                    let targetShadow = this.mkNode(el, targetNode,fn, obj,drag)
                    jsPlumb.connect({source:(node.type === 'start'?endPoints[0]:endPoints[1]),target:targetShadow.spans[0]})
                }
                break
            case 'judge':
                let no =  null,yes = null, todo = null
                for(let span of node.spans) {
                    if(span.agg === 'no') {
                        no = span.target
                        let noNode = this.getID(obj, no)
                        let noShadow = this.mkNode(el, noNode, fn, obj)
                        jsPlumb.connect({source:endPoints[1], target:noShadow.spans[0]})
                    }else if(span.agg === 'yes') {
                        yes = span.target
                        let yesNode = this.getID(obj, yes)
                        let yesShadow = this.mkNode(el, yesNode, fn, obj)
                        jsPlumb.connect({source:endPoints[2], target:yesShadow.spans[0]})
                    }else {
                        todo = span.target
                        let todoNode = this.getID(obj, todo)
                        let todoShadow = this.mkNode(el,todoNode, fn, obj)
                        jsPlumb.connect({source:endPoints[3],target:todoShadow.spans[0]})
                    }
                }
                break
            case 'request':
                let error = null,success = null, down = null
                for(let span of node.spans) {
                    if(span.agg === 'error') {
                        error = span.target
                        let errorNode = this.getID(obj, error)
                        let errorShadow = this.mkNode(el, errorNode, fn, obj)
                        jsPlumb.connect({source:endPoints[1],target:errorShadow.spans[0]})
                    }else if(span.agg === 'success') {
                        success = span.target
                        let successNode = this.getID(obj, success)
                        let successShadow = this.mkNode(el, successNode, fn, obj)
                        jsPlumb.connect({source:endPoints[2],target:successShadow.spans[0]})
                    }else {
                        down = span.target
                        let downNode = this.getID(obj, down)
                        let downShadow = this.mkNode(el, downNode, fn, obj)
                        jsPlumb.connect({source:endPoints[3], target:downShadow.spans[0]})
                    }
                }
                break

        }
        return {
            node:shadow,
            spans:endPoints
        }
    }
    parse(obj, node) {
        let scripts = ''
        let type = node.type
        let content = node.content.replace(/[\s|\r|\n]*/g,'')
        let spans = node.spans
        switch (type) {
            case "start":
                if(content === '开始' || content === '') {
                    scripts += '(){'
                }else {
                    //校验语法
                    let fn = new Function("let " + content)
                    try{
                        fn()
                    }catch(e) {
                        throw node.id + "|语法错误" + e
                        return
                    }
                    scripts += '(' + content + '){'
                }
                if(spans.length > 1){
                    throw node.id + '|语法错误：开始节点流程过多'
                    return
                }else if(spans.length === 1) {
                    let target = spans[0].target
                    let targetNode = this.getID(obj, target)
                    scripts += "\n" + this.parse(obj, targetNode)
                }
                scripts += '}'
                break
            case "assign":
                //赋值语句，多条赋值语句必须用;隔开，数组向后增加=:,数组向前增加:=,数组前面减少#=,数组向后减少=#
                if(content === "赋值" || content ===''){

                }else {
                    let words = content.split(";")
                    let word_arr = []
                    for(let word of words){
                        if(word.indexOf("=:") >= 0) {
                            let _vars = word.split("=:")
                            let tm = `
                                if(${_vars[1]} instanceof Array) {
                                    for(let _ of ${_vars[1]}) {
                                        ${_vars[0]}.push(_)
                                    }
                                }else {
                                    ${_vars[0]}.push(${_vars[1]})
                                }
                            `
                            word_arr.push(tm)
                        }else if(word.indexOf(":=") >= 0) {
                            let _vars = word.split(":=")
                            let tm = `
                                if(${_vars[1]} instanceof Array) {
                                    for(let _ of ${_vars[1]}) {
                                        ${_vars[0]}.unshift(_)
                                    }
                                }else {
                                    ${_vars[0]}.unshift(${_vars[1]})
                                }
                            `
                            word_arr.push(tm)
                        }else {
                            word_arr.push(word)
                        }
                    }
                    scripts = word_arr.join(";")
                }

                if(spans.length > 1){
                    throw node.id + '|语法错误：节点流程过多'
                    return
                }else if(spans.length === 1) {
                    let target = spans[0].target
                    let targetNode = this.getID(obj, target)
                    scripts += "\n" + this.parse(obj, targetNode)
                }
                break
            case "data":
                if(content !== '数据' && content !== '') {
                    //校验语法
                    let fn = new Function("let " + content)
                    try{
                        fn()
                    }catch(e) {
                        throw node.id + "|语法错误" + e
                        return
                    }
                    scripts = "let " + content
                }
                if(spans.length > 1) {
                    throw node.id + "|语法错误：节点流程过多"
                    return
                }else if(spans.length === 1){
                    let target = spans[0].target
                    let targetNode = this.getID(obj,target)
                    scripts += "\n" + this.parse(obj, targetNode)
                }
                break
            case "judge":
                let yesSpan, noSpan, toSpan
                for(let span of spans) {
                    if(span.agg === "yes") {
                        yesSpan = this.getID(obj, span.target)
                    }else if(span.agg === "no") {
                        noSpan = this.getID(obj, span.target)
                    }else if(span.agg === "") {
                        toSpan = this.getID(obj, span.target)
                    }
                }
                scripts = `
                    if(${content}) {
                        ${yesSpan !== null && yesSpan !== undefined?this.parse(obj, yesSpan):''}
                    }${noSpan !== null && noSpan !== undefined?"else{" + this.parse(obj, noSpan) + "}\n":""}
                    ${toSpan !== null && toSpan !== undefined?this.parse(obj,toSpan):""}
                `
                break
            case "end":
                if(content !== "结束" && content !== ''){
                    let arr = content.split(",")
                    if(arr.length > 1) {
                        scripts = `\nreturn [${content}]`
                    }else {
                        scripts = `\nreturn ${content}`
                    }
                }
                break
            case "request":
                let successNode,errorNode,toNode
                for(let span of spans) {
                    if(span.agg === "success") {
                        successNode = this.getID(obj, span.target)
                    }else if(span.agg === "error") {
                        errorNode = this.getID(obj, span.target)
                    }else if(span.agg === ""){
                        toNode = this.getID(obj, span.target)
                    }
                }
                let url = node.getAttr('url')
                let params = node.getAttr("params")
                let method = node.getAttr("method")
                method = method === undefined || method === ''?'get':method
                params = params === undefined || params === ''?'':params
                if(url === undefined || url === '') {
                    throw node.id + "|参数错误：请求URL错误"
                }
                try {
                    new Function("{" + params + "}")()
                }catch(e){
                    throw node.id + "|参数错误：请求参数格式错误"
                    return
                }
                scripts = "axios." + method + `('${url}',
                    ${method === 'get'?'{params:{' + params +'}},':'{' + params + '},'}
                ).then(function(res){
                    let response = res.data
                    ${successNode !== undefined && successNode !== null?this.parse(obj,successNode):''}
                }).catch(function(err) {
                    ${errorNode !== undefined && errorNode !== null?this.parse(obj,errorNode):''}
                })
                    ${toNode !== undefined && toNode !== null?this.parse(obj, toNode):''}
                `
                break
            case "subprocess":
                //判断是否有赋值语句，格式： a = b() => let a = this.b()
                //只有子流程调用，格式： b() => this.b()
                if(content.indexOf("=") >= 0) {
                    let tt = content.split("=")
                    if(tt[0].indexOf("this.") >= 0){
                        scripts = tt[0] + "=" +  "this." + tt[1]
                    }else{
                        scripts = "let " + tt[0] + "=" +  "this." + tt[1]
                    }
                }else {
                    scripts = "this." + content
                }

                if(spans.length > 1) {
                    throw node.id + "|语法错误：节点流程过多"
                    return
                }else if(spans.length === 1) {
                    let target = spans[0].target
                    let targetNode = this.getID(obj, target)
                    scripts += '\n' + this.parse(obj, targetNode)
                }
                break
        }
        return scripts
    }
}